﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Dict.Blo;
using Dict.DataModel;
using ProtoBuf.Message;

namespace UI
{
    public class LevelUpPage : MonoBehaviour
    {
        #region 英雄信息Label
        public UILabel currentLevel;
        public UILabel currentAttack;
        public UILabel currentHP;
        public UILabel curPdef;
        public UILabel curMdef;
        public UILabel curExp;
        public UILabel nextLevel;
        public UILabel nextAttack;
        public UILabel nextHP;
        public UILabel nextPdef;
        public UILabel nextMdef;
        public UISprite expBar;
        public UISprite expAddBar;
        #endregion

        #region 升级消耗
        public List<GameObject > costCardPos;
        public UILabel costCoin;
        Dictionary<int, string> selectedGuids = new Dictionary<int, string>();
        List<GameObject> selectedHeroItems = new List<GameObject>();
        #endregion

        public CharacterRemotePage characterPage;

        public GameObject particlePref1;
        public GameObject particlePref2;
        List<GameObject> particleList = new List<GameObject>();
        List<Vector2> flySpeed = new List<Vector2>();
        GameObject finalParticle;
        bool startFly = false;
        bool startExpGrow = false;
        bool canSelect = true;
        int orderCount = 0;     
        //long oldExpGot = 0;
        int oldLevel = 0;
        int finalWidth = 0;
        int expGrowSpeed = 0;
        int expBarFullWidth = 454;

        private string guid = "";
        private UIHero hero;
        private long costCoinCount;
        
        public void SetHero(string heroGuid)
        {
            guid = heroGuid;
            hero = StaticData.playerData.InstPlayerData.GetUIHero(guid);

            InitInfo();
        }

        private void InitInfo() 
        {
            //清空卡位置
            List<string> list = new List<string>();
            UpdateCostPositions(list);
            DestroyParticlesImdt();
        }

        void UpdatePropertyInfo(long gotExp)
        {
            //基础信息
            int nextLevel = hero.level + 1;
            int maxLevel = DictHeroExpBlo.GetHeroMaxLevel(hero.heroData.quality);
            if (nextLevel > maxLevel)
                nextLevel = maxLevel;
            int nextExp = DictHeroExpBlo.GetHeroLevelExp(hero.heroData.quality, nextLevel);
            
            string attack = ((int)hero.GetPorp(AttributeQueue.Attack)).ToString();
            string hp = ((int)hero.GetPorp(AttributeQueue.Hp)).ToString();
            string pdef = ((int)hero.GetPorp(AttributeQueue.PhyDefend)).ToString();
            string mdef = ((int)hero.GetPorp(AttributeQueue.MagicDefend)).ToString();
            
            currentLevel.GetComponent<LabelNumRoll>().StopRoll();
            currentAttack.GetComponent<LabelNumRoll>().StopRoll();
            currentHP.GetComponent<LabelNumRoll>().StopRoll();
            curPdef.GetComponent<LabelNumRoll>().StopRoll();
            curMdef.GetComponent<LabelNumRoll>().StopRoll();

            int predictLv = DictHeroExpBlo.GetPredictLevelWithExp(hero.heroData.quality, hero.level, gotExp + hero.exp);

            int levelGrow = predictLv - hero.level;
            if (predictLv > StaticData.playerData.level)
                levelGrow = StaticData.playerData.level - hero.level;

            if (levelGrow > 0)
            {
                TableTalentAdvenced heroAdv = hero.TalentData[hero.talentLevel.ToString()].data;

                currentLevel.text = hero.level.ToString();
                currentAttack.text = attack;
                currentHP.text = hp;
                curPdef.text = pdef;
                curMdef.text = mdef;

                this.nextLevel.transform.localPosition = new Vector3(currentLevel.transform.localPosition.x + currentLevel.width, currentLevel.transform.localPosition.y, 0);
                nextAttack.transform.localPosition = new Vector3(currentAttack.transform.localPosition.x + currentAttack.width, currentAttack.transform.localPosition.y, 0);
                nextHP.transform.localPosition = new Vector3(currentHP.transform.localPosition.x + currentHP.width, currentHP.transform.localPosition.y, 0);
                nextPdef.transform.localPosition = new Vector3(curPdef.transform.localPosition.x + curPdef.width, curPdef.transform.localPosition.y, 0);
                nextMdef.transform.localPosition = new Vector3(curMdef.transform.localPosition.x + curMdef.width, curMdef.transform.localPosition.y, 0);

                this.nextLevel.text = "+" + levelGrow.ToString();
                nextAttack.text = "+" + (heroAdv.attGrow * levelGrow).ToString();
                nextHP.text = "+" + (heroAdv.hpGrow * levelGrow).ToString();
                nextPdef.text = "+" + (heroAdv.pdefGrow * levelGrow).ToString();
                nextMdef.text = "+" + (heroAdv.mdefGrow * levelGrow).ToString();
            }
            else
            {
                currentLevel.text = hero.level.ToString();
                currentAttack.text = attack;
                currentHP.text = hp;
                curPdef.text = pdef;
                curMdef.text = mdef;

                this.nextLevel.text = "";
                nextAttack.text = "";
                nextHP.text = "";
                nextPdef.text = "";
                nextMdef.text = "";
            }

            if(levelGrow > 0 || predictLv > hero.level)
            {
                curExp.text = nextExp.ToString() + "/" + nextExp.ToString();
                expBar.gameObject.SetActive(true);
                int w = (int)(hero.exp) * expBarFullWidth / nextExp;
                expBar.width = w > expBarFullWidth ? expBarFullWidth : w;

                if (gotExp > 0)
                {
                    int dx = expBar.width > 0 ? expBar.width : 0;
                    expAddBar.gameObject.SetActive(true);
                    expAddBar.transform.localPosition = new Vector3(expBar.transform.localPosition.x + dx - 6, expBar.transform.localPosition.y, expBar.transform.localPosition.z);
                    expAddBar.width = expBarFullWidth - expBar.width + 6;
                    if (expBarFullWidth == expBar.width)
                        expAddBar.gameObject.SetActive(false);
                }
                else
                {
                    expAddBar.gameObject.SetActive(false);
                }
            }
            else
            {
                expAddBar.gameObject.SetActive(false);
                curExp.text = (hero.exp + gotExp).ToString() + "/" + nextExp.ToString();
                int w = (int)(hero.exp) * expBarFullWidth / nextExp;
                if (w <= 0)
                    expBar.gameObject.SetActive(false);
                else
                {
                    if (w > expBarFullWidth)
                        w = expBarFullWidth;
                    expBar.gameObject.SetActive(true);
                    expBar.width = w;
                }

                if (gotExp > 0)
                {
                    if (w == 0)
                        w += 6;
                    expAddBar.gameObject.SetActive(true);
                    expAddBar.transform.localPosition = new Vector3(expBar.transform.localPosition.x + w - 6, expBar.transform.localPosition.y, expBar.transform.localPosition.z);
                    expAddBar.width = (int)(gotExp) * expBarFullWidth / nextExp;
                }
                else
                {
                    expAddBar.gameObject.SetActive(false);
                }
            }

            if(hero.level >= maxLevel)
            {
                int maxExp = DictHeroExpBlo.GetHeroLevelExp(hero.heroData.quality, maxLevel);
                expBar.gameObject.SetActive(true);
                expBar.width = expBarFullWidth;
                curExp.text = maxExp.ToString() + "/" + maxExp.ToString();
            }

            costCoinCount = gotExp * DictConfigBlo.GetHeroStrengthCostCoinXishu();
            costCoin.text = costCoinCount.ToString();
        }

        public void OnCostPosClick(GameObject obj)
        {
            if (!canSelect)
                return;
            int maxLevel = DictHeroExpBlo.GetHeroMaxLevel(hero.heroData.quality);
            if (hero.level == maxLevel)
            {
                BoxManager.CreatePopupTextBox(TableTextBlo.GetText("hero_strength_max_tip_2"));
                return;
            }

            int index = 0;
            switch(obj.name)
            {
                case "meta1":
                    index = 0;
                    break;
                case "meta2":
                    index = 1;
                    break;
                case "meta3":
                    index = 2;
                    break;
                case "meta4":
                    index = 3;
                    break;
                case "meta5":
                    index = 4;
                    break;
            }
            if(selectedGuids.ContainsKey(index))
            {
                selectedGuids.Remove(index);
                List<string> list = new List<string>();
                foreach(var item in selectedGuids)
                {
                    list.Add(item.Value);
                }
                UpdateCostPositions(list);
            }
            else
            {
                //if (hero.level >= StaticData.playerData.level)
                //{
                //    BoxManager.CreatePopupTextBox(TableTextBlo.GetText("hero_strength_max_tip_2").Replace("\\n", "\n").Replace("\\r", "\r"));
                //    return;
                //}

                List<string> list = StaticData.playerData.InstPlayerData.GetHeroUpgradeAvailableListInOrder();
                if(list.Count <= 0)
                {
                    BoxManager.CreatePopupTextBox(TableTextBlo.GetText("no_material_to_cost").Replace("\\r", "\r").Replace("\\n", "\n"));
                    return;
                }
                string selectedStr = "";
                foreach(var item in selectedGuids)
                {
                    if (selectedStr != "")
                        selectedStr += ",";
                    selectedStr += item.Value;
                }
                PageManager.Instance.OpenPage("HeroSelectPage","guid=" + guid + "&selected=" + selectedStr);
                HeroSelectPage page = (HeroSelectPage)PageManager.Instance.GetDictPage("HeroSelectPage");
                page.m_callback = this.UpdateCostPositions;
            }
        }

        void UpdateCostPositions(List<string> guids)
        {
            foreach(var item in selectedHeroItems)
            {
                item.SetActive(false);
                Destroy(item);
            }
            selectedHeroItems.Clear();
            selectedGuids.Clear();
            
            long gotExp = 0;
            //oldExpGot = gotExp;
            int i = 0;
            foreach (var item in guids)
            {
                UIHero hero = StaticData.playerData.GetUIHero(item);
                gotExp += hero.GetHeroProvideExp();

                if (i >= 5)
                {
                    selectedGuids[i] = item;
                    i++;
                    continue;
                }

                float scale = 0.95f;
                GameObject obj = AssetLoad.ResourceManager.Instance.LoadResource("prefab/HeroIcon") as GameObject;
                GameObject icon = Instantiate(obj);
                icon.GetComponent<HeroIcon>().SetHero(item);
                Destroy(icon.GetComponent<BoxCollider>());
                icon.transform.parent = costCardPos[i].transform;
                icon.transform.localScale = new Vector3(scale, scale, scale);
                icon.transform.localPosition = new Vector3(0, 0, 0);
                
                selectedGuids[i] = item;
                selectedHeroItems.Add(icon);

                i++;
            }
            
            
            UpdatePropertyInfo(gotExp);
        }

        public void OnAutoSelect()
        {
            if (!canSelect)
                return;
            int maxLevel = DictHeroExpBlo.GetHeroMaxLevel(hero.heroData.quality);
            int nextlevel = StaticData.playerData.level < maxLevel ? StaticData.playerData.level + 1 : maxLevel;
            int nextExp = DictHeroExpBlo.GetHeroLevelExp(hero.heroData.quality, nextlevel);
            if (hero.level > StaticData.playerData.level || hero.level == StaticData.playerData.level && hero.exp >= nextExp || hero.level == maxLevel)
            {
                BoxManager.CreatePopupTextBox(TableTextBlo.GetText("hero_strength_max_tip_2").Replace("\\n", "\n").Replace("\\r", "\r"));
                return;
            }

            List<string> listAll = StaticData.playerData.InstPlayerData.GetHeroUpgradeAvailableListInOrder(true);
            if(listAll.Count <= 0)
            {
                //没有蓝色以下的卡可自动添加
                BoxManager.CreatePopupTextBox(TableTextBlo.GetText("no_card_under_blue").Replace("\\n", "\n").Replace("\\r", "\r"));
                return;
            }

            //最多可选多少exp
            long exp1 = DictHeroExpBlo.GetHeroExpToLevel(hero.heroData.quality, hero.level);
            long exp2 = DictHeroExpBlo.GetHeroExpToLevel(hero.heroData.quality, StaticData.playerData.level + 1);
            long maxExpAllow = exp2 - exp1 - hero.exp;

            long totalExp = 0;
            List<string> listSelect = new List<string>();
            for(int i = 0; i < listAll.Count; i++)
            {
                if(i > 4)
                {
                    break;
                }
                UIHero temphero = StaticData.playerData.GetUIHero(listAll[i]);
                long tempexp = temphero.GetHeroProvideExp();
                if (totalExp > maxExpAllow)
                {
                    break;
                }
                else
                {
                    totalExp += tempexp;
                    listSelect.Add(listAll[i]);
                }
            }

            UpdateCostPositions(listSelect);
        }

        bool CheckCostCardList()
        {
            foreach (var item in selectedGuids)
            {
                UIHero heroinfo = StaticData.playerData.GetUIHero(item.Value);
                if(heroinfo.heroData.quality >= (int)QualityValue.PURPLE && heroinfo.heroData.heroClass != (int)HeroClass.Exp_Eater)
                {
                    BoxManager.CreateMessageBoxWithCofirmAndCancelButton(TableTextBlo.GetText("character_upgrade_cost_high_tip"), true, (submit) =>
                    {
                        if (submit)
                        {
                            SendUpgradeMsg();
                        }
                    }, TableTextBlo.GetText("upgrade_cost_high_title"));
                    return false;
                }
            }
            return true;
        }

        public void OnUpgrade()
        {
            if (!canSelect)
                return;

            //没选卡
            if (selectedGuids.Count <= 0)
            {
                BoxManager.CreatePopupTextBox(TableTextBlo.GetText("add_upgrade_cost").Replace("\\n", "\n").Replace("\\r", "\r"));
                return;
            }

            //金币不足
            if (costCoinCount > StaticData.playerData.coin)
            {
                BoxManager.CreatePopupTextBox(TableTextBlo.GetText("coin_lack").Replace("\\n","\n").Replace("\\r", "\r"));
                return;
            }

            //已达到主角等级
            if (hero.level > StaticData.playerData.level)
            {
                BoxManager.CreatePopupTextBox(TableTextBlo.GetText("hero_strength_max_tip_2").Replace("\\n", "\n").Replace("\\r", "\r"));
                return;
            }

            //检查是否要吃紫色以上的卡 character_upgrade_cost_high_tip
            if (!CheckCostCardList())
            {
                return;
            }

            SendUpgradeMsg();
        }

        void SendUpgradeMsg()
        {
            CSWarriorStrengthen msg = new CSWarriorStrengthen();
            msg.guid = guid;

            foreach (var item in selectedGuids)
            {
                UIHero heroinfo = StaticData.playerData.GetUIHero(item.Value);
                BaseResource res = new BaseResource();
                res.guid = item.Value;
                res.id = heroinfo.heroId;

                msg.cost.Add(res);
            }

            NetAPI.SendHttp(OpDefine.CSWarriorStrengthen, msg, UpgradeCallback);
        }

        void UpgradeCallback(NetWork.Packets.Packet packet,bool bsuccess)
        {
            if(bsuccess)
            {
                oldLevel = hero.level;

                SCWarriorStrengthen msg = packet.kBody as SCWarriorStrengthen;
                StaticData.playerData.Delete(msg.cost);
                StaticData.playerData.UpdateHero(msg.guid);

                selectedGuids.Clear();
                canSelect = false;

                PlayEffect();

                StartCoroutine(CallbackUpdate());
            }
        }

        IEnumerator CallbackUpdate()
        {
            yield return new WaitForSeconds(0.4f);
            AudioManager.Instance.PlayUIAudio("jueseqianghua");
            //清空头像
            foreach (var item in selectedHeroItems)
            {
                item.SetActive(false);
                Destroy(item);
            }
            selectedHeroItems.Clear();
        }

        void PlayEffect()
        {
            //属性数字 和 进度条 闪动停止
            this.nextLevel.text = "";
            nextAttack.text = "";
            nextHP.text = "";
            nextPdef.text = "";
            nextMdef.text = "";
            expAddBar.gameObject.SetActive(false);

            //爆花
            foreach (var item in selectedHeroItems)
            {
                GameObject partical = Instantiate(particlePref1);
                partical.SetActive(true);
                partical.transform.parent = item.transform.parent;
                partical.transform.localPosition = new Vector3(0, 0, -600);
                partical.transform.localScale = new Vector3(1, 1, 1);

                particleList.Add(partical);
            }
            
            StartCoroutine(EffectFly());
        }
        
        IEnumerator EffectFly()
        {
            yield return new WaitForSeconds(0.9f);

            foreach (var item in particleList)
            {
                item.transform.parent = gameObject.transform;
            }

            Vector3 pos = characterPage.heroPosition.transform.localPosition;

            flySpeed.Clear();
            foreach (var item in particleList)
            {
                Vector2 v = new Vector2((pos.x - item.transform.localPosition.x), (pos.y + 250 - item.transform.localPosition.y));
                flySpeed.Add(v);
            }
            
            startFly = true;
        }

        IEnumerator DestroyParticles()
        {
            yield return new WaitForSeconds(0.4f);
            foreach (var item in particleList)
            {
                Destroy(item);
            }
            particleList.Clear();

            orderCount++;
            yield return new WaitForSeconds(3f);
            orderCount--;
            if (orderCount <= 0)
                Destroy(finalParticle);
        }

        public void DestroyParticlesImdt()
        {
            canSelect = true;
            startFly = false;
            startExpGrow = false;

            foreach (var item in particleList)
            {
                Destroy(item);
            }
            particleList.Clear();

            Destroy(finalParticle);
        }

        IEnumerator PlayFinalParticle()
        {
            //人物身上的爆花
            if(finalParticle != null)
                Destroy(finalParticle);

            Vector3 pos = characterPage.heroPosition.transform.localPosition;
            finalParticle = Instantiate(particlePref2);
            finalParticle.transform.parent = gameObject.transform;
            finalParticle.transform.localPosition = new Vector3(pos.x, pos.y + 250, - 600);
            finalParticle.transform.localScale = new Vector3(1, 1, 1);
            finalParticle.SetActive(true);

            //属性数字增长
            currentLevel.GetComponent<LabelNumRoll>().SetRoll(int.Parse(currentLevel.text),hero.level);
            currentAttack.GetComponent<LabelNumRoll>().SetRoll((int)float.Parse(currentAttack.text), (int)hero.GetPorp(AttributeQueue.Attack));
            currentHP.GetComponent<LabelNumRoll>().SetRoll((int)float.Parse(currentHP.text), (int)hero.GetPorp(AttributeQueue.Hp));
            curPdef.GetComponent<LabelNumRoll>().SetRoll((int)float.Parse(curPdef.text), (int)hero.GetPorp(AttributeQueue.PhyDefend));
            curMdef.GetComponent<LabelNumRoll>().SetRoll((int)float.Parse(curMdef.text), (int)hero.GetPorp(AttributeQueue.MagicDefend));

            yield return new WaitForSeconds(0.2f);

            //进度条开始涨
            //计算下次进度条长度
            int nextLevel = hero.level + 1;
            int maxLevel = DictHeroExpBlo.GetHeroMaxLevel(hero.heroData.quality);
            if (nextLevel > maxLevel)
                nextLevel = maxLevel;
            int nextExp = DictHeroExpBlo.GetHeroLevelExp(hero.heroData.quality, nextLevel);
            finalWidth = (int)hero.exp * expBarFullWidth / nextExp;
            expGrowSpeed = 3;
            if(hero.level - oldLevel >= 4)
            {
                oldLevel = hero.level - 4;
                expGrowSpeed = 30;
            }
            else if(hero.level - oldLevel >= 1)
            {
                expGrowSpeed = 15;
            }

            startExpGrow = true;
            expBar.gameObject.SetActive(true);
        }

        void Update()
        {
            if(startFly)
            {
                if(particleList.Count > 0 && particleList[0].transform.localPosition.x <= characterPage.heroPosition.transform.localPosition.x)
                {
                    canSelect = true;
                    startFly = false;

                    StartCoroutine(DestroyParticles());
                    StartCoroutine(PlayFinalParticle());

                    return;
                }

                for (int i = 0; i < particleList.Count; i++)
                {
                    GameObject item = particleList[i];
                    //Vector2 v = flySpeed[i];
                    item.transform.localPosition = new Vector3(item.transform.localPosition.x + flySpeed[i].x / (0.7f/Time.deltaTime), item.transform.localPosition.y + flySpeed[i].y / (0.7f / Time.deltaTime), item.transform.localPosition.z);
                }
            }
            if(startExpGrow)
            {
                if(oldLevel < hero.level)
                {
                    if (expBar.width < expBarFullWidth)
                    {
                        if (expBarFullWidth - expBar.width > expGrowSpeed)
                            expBar.width += expGrowSpeed;
                        else
                            expBar.width = expBarFullWidth;

                        int maxLevel = DictHeroExpBlo.GetHeroMaxLevel(hero.heroData.quality);
                        int nextlevel = oldLevel < maxLevel ? oldLevel + 1 : maxLevel;
                        int nextExp = DictHeroExpBlo.GetHeroLevelExp(hero.heroData.quality, nextlevel);
                        curExp.text = (expBar.width * nextExp / expBarFullWidth).ToString() + "/" + nextExp.ToString();
                    }
                    else
                    {
                        expBar.width = 0;
                        oldLevel++;
                    }
                }
                else
                {
                    expGrowSpeed = 3;
                    if (expBar.width < finalWidth)
                    {
                        if (finalWidth - expBar.width > expGrowSpeed)
                            expBar.width += expGrowSpeed;
                        else
                            expBar.width = finalWidth;

                        int maxLevel = DictHeroExpBlo.GetHeroMaxLevel(hero.heroData.quality);
                        int nextlevel = oldLevel < maxLevel ? oldLevel + 1 : maxLevel;
                        int nextExp = DictHeroExpBlo.GetHeroLevelExp(hero.heroData.quality, nextlevel);
                        curExp.text = (expBar.width * nextExp / expBarFullWidth).ToString() + "/" + nextExp.ToString();
                    }
                    else
                    {
                        startExpGrow = false;
                        int maxLevel = DictHeroExpBlo.GetHeroMaxLevel(hero.heroData.quality);
                        int nextlevel = StaticData.playerData.level < maxLevel ? StaticData.playerData.level + 1 : maxLevel;
                        int nextExp = DictHeroExpBlo.GetHeroLevelExp(hero.heroData.quality, nextlevel);
                        curExp.text = hero.exp.ToString() + "/" + nextExp.ToString();
                    }
                }
            }
        }
    }
}